home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * *
- * HPACK Multi-System Archiver *
- * =========================== *
- * *
- * Filesystem-Specific Support Routines *
- * FILESYS.C Updated 03/09/92 *
- * *
- * This program is protected by copyright and as such any use or copying of *
- * this code for your own purposes directly or indirectly is highly uncool *
- * and if you do so there will be....trubble. *
- * And remember: We know where your kids go to school. *
- * *
- * Copyright 1990 - 1992 Peter C.Gutmann. All rights reserved *
- * *
- ****************************************************************************/
-
- #include <ctype.h>
- #include <string.h>
- #ifdef __MAC__
- #include "defs.h"
- #include "arcdir.h"
- #include "error.h"
- #include "flags.h"
- #include "frontend.h"
- #include "hpacklib.h"
- #include "hpaktext.h"
- #include "system.h"
- #include "tags.h"
- #include "fastio.h"
- #include "hpackio.h"
- #else
- #include "defs.h"
- #include "arcdir.h"
- #include "error.h"
- #include "flags.h"
- #include "frontend.h"
- #include "hpacklib.h"
- #include "system.h"
- #include "tags.h"
- #include "io/fastio.h"
- #include "io/hpackio.h"
- #include "language/hpaktext.h"
- #endif /* __MAC__ */
-
- #ifdef __OS2__
-
- /* Prototypes for functions in OS2.C */
-
- void setAccessTime( const char *filePath, const LONG timeStamp );
- void setCreationTime( const char *filePath, const LONG timeStamp );
- void addLongName( const char *filePath, const char *longName );
- void setEAinfo( const char *filePath, const TAGINFO *tagInfo, const FD srcFD );
-
- #endif /* __OS2__ */
-
- /* Take a full pathname, convert it to an OS-compatible format, and extract
- out the path component of the name */
-
- int extractPath( char *fullPath, char *pathName )
- {
- #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __ATARI__ ) || \
- defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __OS2__ ) || \
- defined( __VMS__ )
- BOOLEAN hasDeviceSpec = FALSE;
- #endif /* __AMIGA__ || __ARC__ || __ATARI__ || __MAC__ || __MSDOS__ || __OS2__ || __VMS__ */
- int count, lastSlash = ERROR;
-
- #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
- /* Check whether there is a drive specifier prepended to the path */
- if( fullPath[ 1 ] == ':' )
- {
- lastSlash = 1;
- hasDeviceSpec = TRUE;
- }
- #endif /* __MSDOS__ || __OS2__ */
- #pragma run "/usr/games/moria"
-
- /* Separate the path and filename components, converting directory
- seperators into an OS-compatible format at the same time */
- for( count = 0; fullPath[ count ]; count++ )
- {
- fullPath[ count ] = caseConvert( fullPath[ count ] );
- #if defined( __MSDOS__ )
- /* Fix compiler bug */
- #elif defined( __ATARI__ ) || defined( __OS2__ )
- if( fullPath[ count ] == '\\' )
- fullPath[ count ] = SLASH;
- #endif /* __ATARI__ || __OS2__ */
- #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __MAC__ ) || defined( __VMS__ )
- if( fullPath[ count ] == ':' )
- {
- hasDeviceSpec = TRUE;
- lastSlash = count;
- }
- #endif /* __AMIGA__ || __ARC__ || __MAC__ || __VMS__ */
- if( fullPath[ count ] == SLASH )
- lastSlash = count;
- }
-
- /* If there is only a device/node spec or only a device/node spec and a
- slash we must handle it differently than a normal path: We can't
- stomp the char at lastSlash as we would for a normal path */
- #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
- if( hasDeviceSpec && ( lastSlash == 1 || lastSlash == 2 ) )
- {
- strncpy( pathName, fullPath, ++lastSlash );
- pathName[ lastSlash ] = '\0';
- }
- else
- #elif defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __MAC__ ) || \
- defined( __VMS__ )
- if( hasDeviceSpec && lastSlash != ERROR && \
- ( fullPath[ lastSlash ] == ':' || ( lastSlash && fullPath[ lastSlash - 1 ] == ':' ) ) )
- {
- strncpy( pathName, fullPath, ++lastSlash );
- pathName[ lastSlash ] = '\0';
- }
- else
- #endif /* Various OS-specific drive handling */
- if( lastSlash > 0 )
- {
- /* Create the pathname, stomping the last SLASH for the
- directory-handling functions */
- strncpy( pathName, fullPath, lastSlash );
- pathName[ lastSlash++ ] = '\0';
- }
- else
- {
- if( !lastSlash )
- /* Special case: File is off the root dir */
- *pathName = SLASH;
- pathName[ ++lastSlash ] = '\0';
- }
-
- return( lastSlash );
- }
-
- /* Find the filename component of a given filePath */
-
- char *findFilenameStart( char *filePath )
- {
- char *filePtr = filePath;
- int i;
-
- /* Skip prepended device/node specifier if necessary */
- #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
- if( filePtr[ 1 ] == ':' )
- filePtr += 2;
- #elif defined( __AMIGA__ ) || defined( __MAC__ ) || defined( __VMS__ )
- for( i = 0; filePath[ i ]; i++ )
- if( filePath[ i ] == ':' )
- {
- filePtr = filePath + i + 1; /* +1 to skip ':' */
- break; /* Exit after first colon */
- }
- #endif /* Various OS-specific device/node specifier skips */
-
- /* Find the first char after the last SLASH */
- for( i = 0; filePtr[ i ]; i++ )
- if( filePtr[ i ] == SLASH )
- filePtr += i + 1; /* +1 to skip SLASH */
-
- return( filePtr );
- }
-
- #if 0
- /* Using a given filename, build a path to the directory for temporary files */
-
- BOOLEAN makeTempPath( const char *fileName, char *tempPath )
- {
- char *tmpPath;
-
- /* Build path to keyring file */
- *tempPath = '\0';
- if( ( tmpPath = getenv( TMPPATH ) ) != NULL )
- {
- if( strlen( tmpPath ) + fileName > MAX_PATH )
- error( PATH_ss_TOO_LONG, tmpPath, fileName );
- strcpy( tempPath, tmpPath );
- if( ( i = tempPath[ strlen( tempPath ) - 1 ] ) != SLASH && i != '\\' )
- /* Add trailing slash if necessary */
- strcat( tempPath, SLASH_STR );
- strcat( tempPath, fileName );
- return( TRUE );
- }
-
- /* Couldn't create temp path */
- return( FALSE );
- }
- #endif /* 0 */
-
- /* Check whether a given directory exists */
-
- static BOOLEAN dirnameConflict; /* Whether there is a file/directory
- name conflict */
- BOOLEAN dirExists( char *pathName )
- {
- FILEINFO pathInfo;
- BOOLEAN retVal = FALSE;
- char dirPath[ MAX_PATH ];
- #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __ATARI__ ) || \
- defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
- int strEnd;
- #endif /* __AMIGA__ || __ARC__ || __ATARI__ || __MAC__ || __MSDOS__ || __OS2__ */
-
- dirnameConflict = FALSE;
-
- /* Convert the path into an OS-compatible format */
- extractPath( pathName, dirPath );
-
- #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __ATARI__ ) || \
- defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __OS2__ )
- /* If the pathName is a drive spec only, we need to add a dummy arg.
- The test for whether we need to add the MATCH_ALL is safe since
- extractPath will only leave a trailing slash if the path component
- is a pure drive spec. When we do the findFirst() we will always
- match ".", so there is no need for special-case processing for this */
- strEnd = strlen( dirPath ) - 1;
- if( dirPath[ strEnd ] == ':' || dirPath[ strEnd ] == SLASH )
- strcat( dirPath, MATCH_ALL );
- #endif /* __AMIGA__ || __ARC__ || __ATARI__ || __MAC__ || __MSDOS__ || __OS2__ */
-
- /* See if we can find the given directory */
- if( findFirst( dirPath, ALLFILES_DIRS, &pathInfo ) )
- retVal = TRUE;
- findEnd( &pathInfo );
-
- /* Make sure what we've found is a directory */
- if( retVal && !isDirectory( pathInfo ) )
- /* A filesystem entity of this name already exists */
- dirnameConflict = retVal = TRUE;
-
- return( retVal );
- }
-
- /* Filter out illegal chars. This is virtually identical for the Amiga, MSDOS,
- OS/2, and Unix, the only differences being '#' for the Amiga, ':', ';',
- '+', ',', '=' for the Atari ST, DOS and OS/2, and '&', '!' for Unix. The
- Mac only has ':' as an illegal char, the Arc has its own wierd selection,
- and VMS has everything except '_' illegal. Note that the space char must
- be the first one in the exclusion list if it's used */
-
- #if defined( __MSDOS__ )
- #define BAD_CHARS " \"*+,/:;<=>?[\\]|"
- #elif defined( __AMIGA__ )
- #define BAD_CHARS "\"#$/:<>?|"
- #elif defined( __ARC__ )
- #define BAD_CHARS " \"#$%&*.:^"
- #elif defined( __ATARI__ )
- #define BAD_CHARS " \"*+,/:;<=>?[\\]|"
- #elif defined( __MAC__ )
- #define BAD_CHARS ":"
- #elif defined( __OS2__)
- #define BAD_CHARS " \"*+,/:;<=>?[\\]|"
- #elif defined( __UNIX__ )
- #define BAD_CHARS " !\"$&'*/;<>?[\\]`{|}"
- #elif defined( __VMS__ )
- #define BAD_CHARS " !\"#$%&'()*+,-/:;<=>?@[\\]^`{|}~"
- #else
- #error "Need to define BAD_CHARS in FILESYS.C"
- #endif /* Various OS-specific illegal filename chars */
-
- static inline char xlateChar( const char ch )
- {
- int i;
-
- /* Simple rejection check for non basic ASCII characters */
- if( ch < ' ' || ch > '~' )
- return( '_' );
-
- /* Check for character in exclusion list. OS/2 sets SPACE_OK
- dynamically depending on the filesystem in use */
- for( i = sizeof( BAD_CHARS ) - 2; i >= SPACE_OK; i-- )
- if( ch == BAD_CHARS[ i ] )
- return( '_' );
-
- return( ch );
- }
-
- /* Intelligently truncate a filename to eight-dot-three format for MSDOS,
- MAX_FILENAME for the Amiga, the Mac, and Unix, or eight-dot-three/
- MAX_FILENAME for OS/2 FAT/HPFS. The MSDOS version goes to great lengths
- to produce an optimal translation (ie the best a human could do); the
- Amiga/Mac/Unix versions don't do so well due to the more free-form nature
- of Amiga/Mac/Unix filenames. In any case suffixes of up to three
- characters are preserved (.c, .h, .cpp), otherwise the name is truncated
- at MAX_FILENAME. The VMS one is somewhat complicated since we need to
- truncate either to a rather limited 39.39 format or the canonical RSX-11
- format, with additional complications if the pathname component is a
- directory. The Arc one just truncates down to 10 chars with no extensions,
- which is the ADFS limit and not necessarily imposed by an IFS. However
- under Risc-OS 2 there is no way to tell exactly what to truncate to so we
- use the worst-case length */
-
- #ifdef __VMS__
- static BOOLEAN isDirComponent; /* dir.components get handled specially */
- #endif /* __VMS__ */
-
- static BOOLEAN fileNameTruncated; /* Used by isTruncated() */
-
- static char *truncFileName( char *fileName )
- {
- int i, lastDit, fileNameLength = strlen( fileName );
- static char truncName[ MAX_FILENAME ];
- #if defined( __AMIGA__ ) || defined( __IIGS__ ) || defined( __ATARI__ ) || \
- defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __OS2__ ) || \
- defined( __UNIX__ ) || defined( __VMS__ )
- int j;
- #endif /* __AMIGA__ || __ATARI__ || __IIGS__ || __MAC__ || __MSDOS__ || __OS2__ || __UNIX__ || __VMS__ */
- #if defined( __ATARI__ ) || defined( __MSDOS__ ) || defined( __OS2__ ) || \
- defined( __VMS__ )
- char ch;
- #endif /* __ATARI__ || __MSDOS__ || __OS2__ || __VMS__ */
- #ifdef __VMS__
- int versionNoStart = 0;
- #endif /* __VMS__ */
-
- /* Sanity check in case we're called with a dummy filename */
- if( !fileNameLength )
- return( "" );
-
- #ifdef __VMS__
- if( !isDirComponent )
- /* Prescan the filename for a version number suffix */
- for( i = fileNameLength - 1; i; i-- )
- if( fileName[ i ] == ';' )
- {
- /* Found a possible suffix, check it's valid */
- for( j = i + 1; j < fileNameLength; j++ )
- if( fileName[ j ] < '0' || fileName[ j ] > '9' )
- break;
-
- /* If it's a valid suffix, don't include it in
- further calculations */
- if( j == fileNameLength )
- {
- versionNoStart = fileNameLength = i;
- break;
- }
- }
- #endif /* __VMS__ */
-
- /* Find last dit */
- for( lastDit = fileNameLength - 1; lastDit && fileName[ lastDit ] != '.'; \
- lastDit-- );
- #if defined( __ATARI__ ) || defined( __MSDOS__ )
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- lastDit = fileNameLength;
-
- /* Copy across first 8 chars or up to lastDit */
- for( i = 0; i < 8 && i < lastDit && i < fileNameLength; i++ )
- {
- ch = truncName[ i ] = xlateChar( fileName[ i ] );
- if( ch == '.' )
- truncName[ i ] = '_';
- }
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' )
- {
- j = i;
- truncName[ i++ ] = '.';
-
- /* Check for no dit present. Note that we also check for the
- special case of the dit being at MAX_FILENAME since the
- lastDit loop can stop either at fileNameLength or on a dit */
- if( lastDit == MAX_FILENAME && fileName[ MAX_FILENAME ] != '.' )
- {
- /* No dit, copy across next 3 chars */
- while( i < MAX_FILENAME - 1 && i < fileNameLength )
- truncName[ i++ ] = xlateChar( fileName[ j++ ] );
- }
- else
- {
- /* Copy across last 1-3 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && j < 3 && \
- i <= fileNameLength; fileNameLength--, j++ );
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- }
- #elif defined( __AMIGA__ ) || defined( __UNIX__ )
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- {
- lastDit = fileNameLength;
- j = MAX_FILENAME - 1;
- }
- else
- /* Make sure we preserve at least 3 characters of suffix */
- j = ( MAX_FILENAME - 1 ) - \
- ( ( fileNameLength - lastDit > 3 ) ? 4 : fileNameLength - lastDit );
-
- /* Copy across appropriate no.of chars or up to lastDit */
- for( i = 0; i < j && i < lastDit && i < fileNameLength; i++ )
- truncName[ i ] = xlateChar( fileName[ i ] );
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' && \
- i < MAX_FILENAME && fileNameLength != lastDit )
- {
- truncName[ i++ ] = '.';
-
- /* Copy across last 1-3 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && \
- i <= fileNameLength; fileNameLength--, j++ );
- if( j > 3 && fileNameLength == MAX_FILENAME )
- j = 3; /* Handle overshoot */
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- #elif defined( __ARC__ )
- /* Just copy across the first 10 chars (the ADFS limit) */
- for( i = 0; i < 10 && i < fileNameLength; i++ )
- truncName[ i ] = xlateChar( fileName[ i ] );
- #elif defined( __MAC__ )
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- {
- lastDit = fileNameLength;
- j = MAX_FILENAME - 1;
- }
- else
- /* Make sure we preserve at least 3 characters of suffix */
- j = ( MAX_FILENAME - 1 ) - \
- ( ( fileNameLength - lastDit > 3 ) ? 4 : fileNameLength - lastDit );
-
- /* Copy across appropriate no.of chars or up to lastDit */
- for( i = 0; i < j && i < lastDit && i < fileNameLength; i++ )
- truncName[ i ] = xlateChar( fileName[ i ] );
-
- /* If the name starts with a dit, zap it (device names start with dits) */
- if( truncName[ 0 ] == '.' )
- truncName[ 0 ] = '_';
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' && \
- i < MAX_FILENAME && fileNameLength != lastDit )
- {
- j = i;
- truncName[ i++ ] = '.';
-
- /* Copy across last 1-3 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && \
- i <= fileNameLength; fileNameLength--, j++ );
- if( j > 3 && fileNameLength == MAX_FILENAME )
- j = 3; /* Handle overshoot */
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- #elif defined( __OS2__ )
- if( destIsHPFS )
- {
- /* Truncate to HPFS specs */
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- {
- lastDit = fileNameLength;
- j = MAX_FILENAME - 1;
- }
- else
- /* Make sure we preserve at least 3 characters of suffix */
- j = ( MAX_FILENAME - 1 ) - \
- ( ( fileNameLength - lastDit > 3 ) ? 4 : fileNameLength - lastDit );
-
- /* Copy across appropriate no.of chars or up to lastDit */
- for( i = 0; i < j && i < lastDit && i < fileNameLength; i++ )
- truncName[ i ] = xlateChar( fileName[ i ] );
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' && \
- i < MAX_FILENAME && fileNameLength != lastDit )
- {
- j = i;
- truncName[ i++ ] = '.';
-
- /* Copy across last 1-3 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && \
- i <= fileNameLength; fileNameLength--, j++ );
- if( j > 3 && fileNameLength == MAX_FILENAME )
- j = 3; /* Handle overshoot */
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- }
- else
- {
- /* Truncate to 8.3 */
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- lastDit = fileNameLength;
-
- /* Copy across first 8 chars or up to lastDit */
- for( i = 0; i < 8 && i < lastDit && i < fileNameLength; i++ )
- {
- ch = truncName[ i ] = xlateChar( fileName[ i ] );
- if( ch == '.' )
- truncName[ i ] = '_';
- }
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' )
- {
- j = i;
- truncName[ i++ ] = '.';
-
- /* Check for no dit present. Note that we also check for the
- special case of the dit being at MAX_FILENAME since the
- lastDit loop can stop either at fileNameLength or on a dit */
- if( lastDit == MAX_FILENAME && fileName[ MAX_FILENAME ] != '.' )
- {
- /* No dit, copy across next 3 chars */
- while( i < MAX_FILENAME - 1 && i < fileNameLength )
- truncName[ i++ ] = xlateChar( fileName[ j++ ] );
- }
- else
- {
- /* Copy across last 1-3 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && j < 3 && \
- i <= fileNameLength; fileNameLength--, j++ );
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- }
- }
- #elif defined( __VMS__ )
- /* Check whether we need to truncate to RSX-11 format */
- if( sysSpecFlags & SYSPEC_RSX11 )
- {
- /* If it's a directory, just copy across up to the first 9 chars */
- if( isDirComponent )
- for( i = 0; i < 9 && i < fileNameLength; i++ )
- {
- ch = truncName[ i ] = xlateChar( fileName[ i ] );
- if( ch == '.' )
- truncName[ i ] = '_';
- }
- else
- {
- /* Truncate to 9.3 */
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- lastDit = fileNameLength;
-
- /* Copy across first 9 chars or up to lastDit */
- for( i = 0; i < 9 && i < lastDit && i < fileNameLength; i++ )
- {
- ch = truncName[ i ] = xlateChar( fileName[ i ] );
- if( ch == '.' )
- truncName[ i ] = '_';
- }
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' )
- {
- j = i;
- truncName[ i++ ] = '.';
-
- /* Check for no dit present. Note that we also check for the
- special case of the dit being at MAX_FILENAME since the
- lastDit loop can stop either at fileNameLength or on a dit */
- if( lastDit == MAX_FILENAME && fileName[ MAX_FILENAME ] != '.' )
- {
- /* No dit, copy across next 3 chars */
- while( i < MAX_FILENAME - 1 && i < fileNameLength )
- truncName[ i++ ] = xlateChar( fileName[ j++ ] );
- }
- else
- {
- /* Copy across last 1-3 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && j < 3 && \
- i <= fileNameLength; fileNameLength--, j++ );
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- }
- }
- }
- else
- {
- /* If it's a directory, just copy across up to the first 39 chars */
- if( isDirComponent )
- for( i = 0; i < 39 && i < fileNameLength; i++ )
- {
- ch = truncName[ i ] = xlateChar( fileName[ i ] );
- if( ch == '.' )
- truncName[ i ] = '_';
- }
- else
- {
- /* Truncate to 39.39 */
- if( !lastDit || fileName[ fileNameLength - 1 ] == '.' )
- lastDit = fileNameLength;
-
- /* Copy across first 39 chars or up to lastDit */
- for( i = 0; i < 39 && i < lastDit && i < fileNameLength; i++ )
- {
- ch = truncName[ i ] = xlateChar( fileName[ i ] );
- if( ch == '.' )
- truncName[ i ] = '_';
- }
-
- /* Add dit and continue if necessary */
- if( i < fileNameLength && fileName[ fileNameLength - 1 ] != '.' )
- {
- j = i;
- truncName[ i++ ] = '.';
-
- /* Check for no dit present. Note that we also check for the
- special case of the dit being at MAX_FILENAME since the
- lastDit loop can stop either at fileNameLength or on a dit */
- if( lastDit == MAX_FILENAME && fileName[ MAX_FILENAME ] != '.' )
- {
- /* No dit, copy across next 39 chars */
- while( i < MAX_FILENAME - 1 && i < fileNameLength )
- truncName[ i++ ] = xlateChar( fileName[ j++ ] );
- }
- else
- {
- /* Copy across last 1-39 chars after dit */
- for( j = 0; fileName[ fileNameLength - 1 ] != '.' && j < 39 && \
- i <= fileNameLength; fileNameLength--, j++ );
- while( j-- )
- truncName[ i++ ] = xlateChar( fileName[ fileNameLength++ ] );
- }
- }
- }
- }
-
- /* Finally, append the version number if there is one */
- if( versionNoStart )
- while( fileName[ fileNameLength ] )
- truncName[ i++ ] = fileName[ fileNameLength++ ];
- #else
- #error "Need to implement truncFileName() in FILESYS.C"
- #endif /* Various OS-specific defines */
- truncName[ i ] = '\0';
-
- fileNameTruncated = strcmp( fileName, truncName );
- return( truncName );
- }
-
- /****************************************************************************
- * *
- * File Type Handling *
- * *
- ****************************************************************************/
-
- #if defined( __ARC__ ) || defined( __IIGS__ ) || defined( __MAC__ )
-
- /* Routines to handle user-defined type settings. These are extension-type
- associations of the form <file extension> = <type information>, and can
- be used to add new types and override built-in ones */
-
- #define EXT_LENGTH 8 /* 7 chars + '\0' */
-
- #if defined( __ARC__ )
- #define TYPE_LENGTH sizeof( WORD ) /* Length of file type field */
- #define CREATOR_LENGTH 0 /* No secondary type */
- #elif defined( __IIGS__ )
- #define TYPE_LENGTH sizeof( WORD ) /* Length of file type field */
- #define CREATOR_LENGTH sizeof( LONG ) /* Length of auxType field */
- #elif defined( __MAC__ )
- #define TYPE_LENGTH sizeof( LONG ) /* Length of file type field */
- #define CREATOR_LENGTH sizeof( LONG ) /* Length of file creator field */
- #endif /* Various system-dependant file type sizes */
-
- typedef struct TA {
- struct TA *next; /* The next header in the list */
- char extension[ EXT_LENGTH ]; /* The file extension */
- LONG type; /* The file type */
- #if defined( __IIGS__ ) || defined( __MAC__ )
- LONG creator; /* The file creator */
- #endif /* __IIGS__ || __MAC__ */
- } TYPE_ASSOC;
-
- static TYPE_ASSOC *typeAssocListHead = NULL;
-
- void addTypeAssociation( char *assocData )
- {
- TYPE_ASSOC *namePtr, *prevPtr, *newRecord;
- char *typePtr, *creatorPtr;
- char type[ TYPE_LENGTH ];
- #if defined( __IIGS__ ) || defined( __MAC__ )
- char creator[ CREATOR_LENGTH ];
- #endif /* __IIGS__ || __MAC__ */
-
- /* Break up the assocData string into its component parts */
- for( typePtr = assocData; *typePtr && *typePtr != '='; typePtr++ );
- if( !*typePtr ) /* Check for end of string reached */
- return;
- for( creatorPtr = typePtr; *creatorPtr && *creatorPtr != ','; creatorPtr++ );
- #if defined( __IIGS__ ) || defined( __MAC__ )
- if( !*creatorPtr ) /* Check for end of string reached */
- return;
- #endif /* __IIGS__ || __MAC__ */
- *typePtr++ = *creatorPtr++ = '\0'; /* Break up string */
-
- /* Perform some simple range checks. Note that the creatorPtr check
- works even when no creator is present since it checks for spurious
- noise at the end of the string */
- if( strlen( assocData ) > EXT_LENGTH || \
- strlen( creatorPtr ) > CREATOR_LENGTH || \
- strlen( typePtr ) > TYPE_LENGTH )
- return;
-
- /* Pad type and creator with zeroes if necessary */
- memset( type, 0, TYPE_LENGTH );
- memcpy( type, typePtr, TYPE_LENGTH );
- #if defined( __IIGS__ ) || defined( __MAC__ )
- memset( creator, 0, CREATOR_LENGTH );
- memcpy( creator, creatorPtr, CREATOR_LENGTH );
- #endif /* __IIGS__ || __MAC__ */
-
- for( namePtr = typeAssocListHead; namePtr != NULL; \
- prevPtr = namePtr, namePtr = namePtr->next )
- /* Check whether we've already processed an association of this name */
- if( !strcmp( assocData, namePtr->extension ) )
- return;
-
- /* We have reached the end of the list without a match, so we add this
- archive name to the list */
- if( ( newRecord = ( TYPE_ASSOC * ) hmalloc( sizeof( TYPE_ASSOC ) ) ) == NULL )
- error( OUT_OF_MEMORY );
- strcpy( newRecord->extension, assocData );
- memcpy( &newRecord->type, type, TYPE_LENGTH );
- #if defined( __IIGS__ ) || defined( __MAC__ )
- memcpy( &newRecord->creator, creator, CREATOR_LENGTH );
- #endif /* __IIGS__ || __MAC__ */
- newRecord->next = NULL;
- if( typeAssocListHead == NULL )
- typeAssocListHead = newRecord;
- else
- prevPtr->next = newRecord;
- return;
- }
-
- /* Free up the memory used by the list of archive names */
-
- void freeTypeAssociations( void )
- {
- TYPE_ASSOC *namePtr = typeAssocListHead, *headerPtr;
-
- /* A simpler implementation of the following would be:
- for( namePtr = typeAssocListHead; namePtr != NULL; namePtr = namePtr->next )
- hfree( namePtr );
- However this will fail on some systems since we will be trying to
- read namePtr->next out of a record we have just free()'d */
- while( namePtr != NULL )
- {
- headerPtr = namePtr;
- namePtr = namePtr->next;
- hfree( headerPtr );
- }
- }
-
- /* Try and determine the type of a file based on the filename suffix. Note
- that sometimes we can't tell the exact type from the suffix (.hpk, Unix
- executables), and sometimes the formats are incompatible, undocumented,
- and constantly changing (MS Word) so we don't bother */
-
- #if defined( __ARC__ )
-
- typedef struct {
- char *suffix; /* The suffix for the file */
- WORD type; /* The file type */
- } FILE_TYPEINFO;
-
- static FILE_TYPEINFO typeInfo[] =
- {
- { "arc", 0x0DDC }, /* ARC archive (Sparc archiver) */
- { "arj", 0x0DDC }, /* ARJ archive (Sparc archiver) */
- { "bat", 0x0FDA }, /* MSDOS batch file */
- { "bmp", 0x069C }, /* Windoze BMP graphics file */
- { "c", 0x0FFF }, /* C code file */
- { "cgm", 0x0405 }, /* Computer Graphics Metafile */
- { "com", 0x0FD8 }, /* MSDOS executable */
- { "csv", 0x0DFE }, /* Comma Seperated Variable file */
- { "dif", 0x0DFD }, /* DIF spreadsheet data */
- { "dbf", 0x0DB3 }, /* dBase III file */
- { "dvi", 0x0CE5 }, /* DVI (actually TeX) file */
- { "dxf", 0x0DEA }, /* DXF portalbe CAD file format */
- { "h", 0x0FFF }, /* C header files */
- { "gif", 0x0695 }, /* GIF graphics file */
- { "exe", 0x0FD9 }, /* MSDOS executable */
- { "iff", 0x0693 }, /* Amiga IFF graphics file */
- { "img", 0x0692 }, /* Atari IMG graphics file */
- { "fits", 0x06A3 }, /* Flexible Image Transport Sys. file */
- { "jpg", 0x0C85 }, /* JPEG graphics file */
- { "lzh", 0x0DDC }, /* Lharc archive (Sparc archiver) */
- { "mac", 0x0694 }, /* MacPaint graphics file */
- { "mod", 0x0CB6 }, /* Amiga .MOD sound file */
- { "ndx", 0x0DB1 }, /* dBase III index file */
- { "pbm", 0x069E }, /* PBM graphics file */
- { "pcx", 0x0697 }, /* PCX graphics file */
- { "pi1", 0x0691 }, /* Atari Degas graphics file */
- { "pi2", 0x0691 }, /* Atari Degas graphics file */
- { "pi3", 0x0691 }, /* Atari Degas graphics file */
- { "pi4", 0x0691 }, /* Atari Degas graphics file */
- { "ps", 0x0FF5 }, /* PostScript file */
- { "qrt", 0x0698 }, /* QRT graphic file. The 'Q' is for 'slow' */
- { "rf", 0x0FC9 }, /* Sun raster file */
- { "rle", 0x06A1 }, /* Unix RLE image */
- { "rtf", 0x0FFF }, /* Rich Text Format data */
- { "tar", 0x0C46 }, /* tar'd files */
- { "tif", 0x0FF0 }, /* TIFF graphics etc data */
- { "txt", 0x0FFF }, /* Text files */
- { "uue", 0x0DDC }, /* uuencoded file (Sparc archiver) */
- { "wks", 0x0DB0 }, /* Lotus 123 v1 worksheet */
- { "wk1", 0x0DB0 }, /* Lotus 123 v2 worksheet */
- { "xbm", 0x069E }, /* XBM graphics file */
- { "z", 0x0DDC }, /* compress file (Sparc archiver) */
- { "zip", 0x0DDC }, /* ZIP archive (Sparc archiver) */
- /* { "", 0x0FE6 }, \* Unix executable */
- /* { "???", 0x0DB2 }, \* dBase II file */
- /* { "???", 0x0DB4 }, \* SuperCalc III file */
- { "", 0 } /* End marker */
- };
-
- #elif defined( __IIGS__ )
-
- typedef struct {
- char *suffix; /* The suffix for the file */
- WORD type; /* The file type */
- LONG auxType; /* The file auxiliary type */
- } FILE_TYPEINFO;
-
- static FILE_TYPEINFO typeInfo[] =
- {
- { "", 0, 0L } /* End marker */
- };
-
- #elif defined( __MAC__ )
-
- typedef struct {
- char *suffix; /* The suffix for the file */
- LONG type; /* The file type */
- LONG creator; /* The file creator */
- } FILE_TYPEINFO;
-
- static FILE_TYPEINFO typeInfo[] =
- {
- { "c", 'TEXT', 'KAHL' }, /* ThinkC C source */
- { "cpt", 'PACT', 'CPCT' }, /* Compact archive */
- { "ctx", 'PGP ', 'PGP ' }, /* PGP ciphertext file */
- { "dbf", 'F+DB', 'FOX+' }, /* FoxBase+ (.dbf) */
- { "dbt", 'F+DT', 'FOX+' }, /* FoxBase+ (.dbt) */
- { "frm", 'F+FR', 'FOX+' }, /* FoxBase+ (.frm) */
- { "gif", 'GIFf', '8BIM' }, /* GIF graphics file (Photoshop) */
- { "h", 'TEXT', 'KAHL' }, /* ThinkC C source */
- { "hpk", 'HPAK', 'HPAK' }, /* HPACK archive */
- { "idx", 'F+IX', 'FOX+' }, /* FoxBase+ (.idx) */
- { "jpg", 'JFIF', '8BIM' }, /* JPEG graphics file (Photoshop) */
- { "mac", 'PNTG', 'MPNT' }, /* Macpaint graphics file */
- { "p", 'TEXT', 'PJMM' }, /* Think Pascal source */
- { "pas", 'TEXT', 'PJMM' }, /* Think Pascal source */
- /* { "pas", 'TEXT', 'MPS ' }, \* MPW Pascal source */
- { "pit", 'PIT ', 'PIT ' }, /* Packit archive */
- { "rpt", 'F+RP', 'FOX+' }, /* FoxBase+ (.rpt) */
- { "rtf", 'WDBN', 'MSWD' }, /* Rich Text Format (MS Word) */
- { "scx", 'F+FM', 'FOX+' }, /* FoxBase+ (.scx) */
- { "sit", 'SIT!', 'SIT!' }, /* StuffIt archive */
- { "txt", 'TEXT', 'ttxt' }, /* Generic text (TeachText) */
- { "vue", 'F+VU', 'FOX+' }, /* FoxBase+ (.vue) */
- { "xls", 'XLS ', 'XCEL' }, /* Excel worksheet */
- { "xlm", 'XLM ', 'XCEL' }, /* Excel macros */
- { "xlc", 'XLC ', 'XCEL' }, /* Excel charts */
- { "xlw", 'XLW ', 'XCEL' }, /* Excel workspace document */
- { "tif", 'TIFF', 'dpnt' }, /* TIFF graphics file (Desk Paint) */
- { "zip", 'pZIP', 'pZIP' }, /* Info-ZIP archive */
- /* { "doc", 'WDBN', 'MSWD' }, \* MS Word document (sometimes) */
- /* { "???", 'GLOS', 'MSWD' }, \* MS Word glossary */
- /* { "dic", 'DICT', 'MSWD' }, \* MS Word dictionary */
- { "", 0L, 0L }, /* End marker */
- };
-
- #endif /* Various OS-specific file type info */
-
- void findFileType( FILEHDRLIST *fileInfoPtr )
- {
- TYPE_ASSOC *assocInfoPtr;
- char *suffixPtr, *fileName = fileInfoPtr->fileName;
- int i;
-
- /* If we already have type info, return now */
- if( fileInfoPtr->type )
- return;
-
- /* Find the filename suffix */
- for( suffixPtr = fileName + strlen( fileName ) - 1; \
- suffixPtr != fileName && *suffixPtr != '.'; \
- suffixPtr-- );
- if( suffixPtr++ == fileName ) /* Move past dit, return if no suffix */
- return;
-
- /* First look through the user-defined types. These can override the
- built-in ones */
- for( assocInfoPtr = typeAssocListHead; assocInfoPtr != NULL; assocInfoPtr = assocInfoPtr->next )
- if( !stricmp( assocInfoPtr->extension, suffixPtr ) )
- {
- fileInfoPtr->type = assocInfoPtr->type;
- #if defined( __IIGS__ )
- fileInfoPtr->auxType = assocInfoPtr->auxType;
- #elif defined( __MAC__ )
- fileInfoPtr->creator = assocInfoPtr->creator;
- #endif /* Setting of other file info */
- return;
- }
-
- /* Then look through the built-in suffix table trying to match the file
- suffix */
- for( i = 0; *typeInfo[ i ].suffix; i++ )
- if( !stricmp( typeInfo[ i ].suffix, suffixPtr ) )
- {
- fileInfoPtr->type = typeInfo[ i ].type;
- #if defined( __IIGS__ )
- fileInfoPtr->auxType = typeInfo[ i ].auxType;
- #elif defined( __MAC__ )
- fileInfoPtr->creator = typeInfo[ i ].creator;
- #endif /* Setting of other file info */
- return;
- }
- }
-
- #endif /* __ARC__ || __IIGS__ || __MAC__ */
-
- /****************************************************************************
- * *
- * Directory-Extraction Routines *
- * *
- ****************************************************************************/
-
- /* Build the path to a given directory index, truncating names if necessary */
-
- char *getPath( WORD dirNo )
- {
- WORD dirStack[ MAX_PATH ]; /* We'll run out of path length before we run
- out of directory stack so this is safe */
- static char pathName[ MAX_PATH ];
- int stackIndex = 0, pathLen = 0;
- char *dirNamePtr;
-
- /* Get a chain of directories from the root to the desired directory */
- if( dirNo )
- do
- dirStack[ stackIndex++ ] = dirNo;
- while( ( dirNo = getParent( dirNo ) ) && stackIndex <= MAX_PATH );
-
- /* Build the path to the current directory */
- *pathName = '\0';
- while( stackIndex )
- {
- #ifdef __VMS__
- isDirComponent = TRUE;
- #endif /* __VMS__ */
- dirNamePtr = truncFileName( getDirName( dirStack[ --stackIndex ] ) );
- if( ( pathLen += strlen( dirNamePtr ) ) >= MAX_PATH - 1 )
- error( PATH_s__TOO_LONG, pathName );
- strcat( pathName, dirNamePtr );
- strcat( pathName, SLASH_STR );
- }
-
- return( pathName );
- }
-
- /* Recreate a directory tree stored within an archive */
-
- void makeDirTree( void )
- {
- char dirPath[ MAX_PATH ], *pathName;
- int outputPathLen = basePathLen;
- WORD count;
- BOOLEAN inPosition = FALSE;
- long dataLen;
- TAGINFO tagInfo;
- #if defined( __MSDOS__ )
- /* Bypass compiler bug */
- #elif defined( __MAC__ ) || defined( __OS2__ )
- LONG timeStamp;
- #elif defined( __UNIX__ )
- struct utimbuf timeStamp;
- #endif /* Various OS-specific attribute variables */
-
- skipDist = 0L;
- strcpy( dirPath, basePath ); /* We have already checked the validity
- of basePath in handleArchive() */
- getFirstDir(); /* Skip archive root directory */
- for( count = getNextDir(); count != END_MARKER; count = getNextDir() )
- {
- /* Get the path to the current directory. Note that getPath() returns
- SLASH at the end of the pathname. This is then stomped by the call
- to extractPath() in dirExists(), and is in fact essential since
- otherwise extractPath() will treat the last directory name as a filename */
- pathName = getPath( count );
- if( outputPathLen + strlen( pathName ) >= MAX_PATH )
- error( PATH_ss__TOO_LONG, basePath, pathName );
- strcpy( dirPath + outputPathLen, pathName );
-
- /* Try and create the new directory if it's marked for creation and
- doesn't already exist */
- if( getDirTaggedStatus( count ) && !dirExists( dirPath ) )
- {
- dirPath[ strlen( dirPath ) - 1 ] = '\0'; /* Stomp final SLASH */
- #ifndef GUI
- hprintfs( MESG_CREATING_DIRECTORY_s, ( fileNameTruncated ) ? \
- getDirName( count ) : dirPath );
- if( fileNameTruncated )
- hprintfs( MESG_AS_s, dirPath );
- hputchars( '\n' );
- #endif /* !GUI */
- if( hmkdir( dirPath, MKDIR_ATTR ) == IO_ERROR )
- error( CANNOT_CREATE_DIR, dirPath );
-
- /* Handle tagged information if necessary */
- if( ( flags & STORE_ATTR ) && ( dataLen = getDirAuxDatalen( count ) ) )
- {
- /* Move to the correct position in the archive if we're not
- already there */
- if( !inPosition )
- {
- movetoDirData();
- skipDist = 0L; /* Skipped data has been bypassed */
- inPosition = TRUE;
- }
- else
- skipToData();
-
- /* Grovel through the directory data field looking for
- attribute tags */
- while( dataLen )
- switch( readTag( &dataLen, &tagInfo ) )
- {
- case TAGCLASS_ATTRIBUTE:
- /* Read in the attributes and set them */
- hchmod( dirPath, readAttributeData( tagInfo.tagID ) );
- break;
-
- #if defined( __MSDOS__ )
- /* Fix compiler bug */
- #elif defined( __MAC__ )
- case TAGCLASS_TIME:
- /* Read in the file times and set them */
- if( tagInfo.tagID == TAG_BACKUP_TIME )
- /* Set file's backup time */
- setBackupTime( dirPath, fgetLong() );
- else
- if( tagInfo.tagID == TAG_CREATION_TIME )
- /* Set file's creation time */
- setCreationTime( dirPath, fgetLong() );
- else
- skipSeek( tagInfo.dataLength );
- break;
-
- case TAGCLASS_MISC:
- if( tagInfo.tagID == TAG_VERSION_NUMBER )
- setVersionNumber( dirPath, ( BYTE ) fgetWord() );
- else
- skipSeek( tagInfo.dataLength );
- break;
- #elif defined( __OS2__ )
- case TAGCLASS_TIME:
- /* Read in the file times and set them */
- if( tagInfo.tagID == TAG_ACCESS_TIME )
- /* Set file's access time */
- setAccessTime( dirPath, fgetLong() );
- else
- if( tagInfo.tagID == TAG_CREATION_TIME )
- /* Set file's creation time */
- setCreationTime( dirPath, fgetLong() );
- else
- skipSeek( tagInfo.dataLength );
- break;
-
- case TAGCLASS_ICON:
- /* Set the icon EA if possible */
- if( tagInfo.tagID == TAG_OS2_ICON )
- setEAinfo( dirPath, &tagInfo, archiveFD );
- else
- skipSeek( tagInfo.dataLength );
- break;
-
- case TAGCLASS_MISC:
- /* Set the longname EA if possible */
- if( tagInfo.tagID == TAG_LONGNAME || \
- tagInfo.tagID == TAG_OS2_MISC_EA )
- {
- setEAinfo( dirPath, &tagInfo, archiveFD );
- break;
- }
- else
- skipSeek( tagInfo.dataLength );
- break;
- #elif defined( __UNIX__ )
- case TAGCLASS_TIME:
- /* Read in the file times and set them */
- if( tagInfo.tagID == TAG_CREATION_TIME )
- {
- timeStamp.actime = fgetLong();
- timeStamp.modtime = getDirTime( count );
- utime( dirPath, &timeStamp );
- }
- else
- skipSeek( tagInfo.dataLength );
- break;
- #endif /* Various OS-dependant attribute reads */
-
- default:
- /* We don't know what to do with this tag, skip it */
- skipSeek( tagInfo.dataLength );
- break;
- }
- }
-
- #ifdef __OS2__
- /* If we've truncated the directory name, add the full name as
- an EA */
- if( fileNameTruncated )
- addLongName( dirPath, getDirName( count ) );
- #endif /* __OS2__ */
-
- /* Give the directory its real date if necessary. We don't
- need to check that the open is successful since we've just
- created the directory so we know it exists */
- if( !( flags & TOUCH_FILES ) )
- setDirecTime( dirPath, getDirTime( count ) );
- }
- else
- {
- /* Complain if an entity of this name already exists and skip it
- and all the files and directories contained within it */
- if( dirnameConflict )
- {
- pathName[ strlen( pathName ) - 1 ] = '\0'; /* Stomp final SLASH */
- #ifdef GUI
- alert( ALERT_DIRNAME_CONFLICTS_WITH_FILE, pathName );
- #else
- hprintf( WARN_DIRNAME_s_CONFLICTS_WITH_FILE, pathName );
- #endif /* GUI */
- selectDirNo( count, FALSE );
- }
-
- /* Skip the data for this directory */
- skipDist += ( long ) getDirAuxDatalen( count );
- }
-
- /* Make sure we don't get a "Nothing to do" error if there are no
- files to extract */
- archiveChanged = TRUE;
- }
-
- /* Move back to the start of the archive if necessary */
- if( inPosition )
- vlseek( 0L, SEEK_SET );
- }
-
- /****************************************************************************
- * *
- * Archive Path-Handling Routines *
- * *
- ****************************************************************************/
-
- /* Various vars used by several routines */
-
- static int internalPathLen;
-
- /* Build the path within the archive to a given file */
-
- char *buildInternalPath( FILEHDRLIST *infoPtr )
- {
- static char internalPath[ MAX_PATH ];
- char *truncName;
-
- strcpy( internalPath, ( flags & STORE_PATH ) ? \
- getPath( infoPtr->data.dirIndex ) : "" );
- #ifdef __VMS__
- isDirComponent = FALSE;
- #endif /* __VMS__ */
- truncName = truncFileName( infoPtr->fileName );
- if( ( internalPathLen = strlen( internalPath ) + strlen( truncName ) ) >= MAX_PATH )
- error( PATH_ss_TOO_LONG, internalPath, truncName );
- strcat( internalPath, truncName );
- return( internalPath );
- }
-
- /* Build the path outside the archive to a given file */
-
- char *buildExternalPath( FILEHDRLIST *infoPtr )
- {
- static char externalPath[ MAX_PATH ];
- char *pathPtr;
-
- strcpy( externalPath, basePath );
- pathPtr = buildInternalPath( infoPtr );
- if( basePathLen + internalPathLen >= MAX_PATH )
- error( PATH_ss_TOO_LONG, externalPath, pathPtr );
- strcat( externalPath, pathPtr );
- return( externalPath );
- }
-
- BOOLEAN isTruncated( void )
- {
- return( fileNameTruncated );
- }
-